package oceanlife.pathfinding;

import java.util.Arrays;
import java.util.HashSet;

import oceanlife.Agent;

public class Edge implements Comparable<Edge> {
	private Pnt[] pointsOnEdge = null;
	private double minimumWidth = Double.MAX_VALUE;
	public HashSet<Agent> agentsOnEdge = new HashSet<Agent>();
	private double weight;
	private double efficiency;
	private double length;
	
	public Edge(Edge ed){
		this.weight = ed.weight;
		this.efficiency = ed.efficiency;
		this.length = ed.length;
		this.pointsOnEdge = ed.pointsOnEdge.clone();
		this.minimumWidth = ed.minimumWidth;
		this.agentsOnEdge = ed.agentsOnEdge;
	}


	public Edge(Pnt[] pOE){
		//this(pOE,0.0);
		this(pOE,getLength(pOE),Double.MAX_VALUE,new HashSet<Agent>(),1.0,0.0);
	}
	
	private static double getLength(Pnt[] pOE) {
		double length = 0;
		for(int i = 0;i < pOE.length-1 ; i++){
			length += pOE[i].distanceTo(pOE[i+1]);
		}
		return length;
	}


	//public Edge(Pnt[] pOE, double inputLength){
	//}

	public Edge(Pnt[] pOE, double length, double minimumWidth, HashSet<Agent> agentsOnEdge,double efficiency,double weigth) {
		//System.out.println(weight);
		this.length = length;
		this.efficiency = efficiency;
		if(weigth == 0.0){
			if(efficiency == 0){
				this.weight = Double.MAX_VALUE;
			} else {
				this.weight = length/efficiency;
			}
		} else {
			this.weight = weigth;
		}
		this.pointsOnEdge = pOE;
		this.agentsOnEdge = agentsOnEdge;
		this.minimumWidth = minimumWidth;
	}
	
	public int getPointsAmount(){
		return pointsOnEdge.length;
	}

	public Edge reverse(){	
		Pnt[] pnts = new Pnt[this.pointsOnEdge.length];
		for(int i = 0;i < this.pointsOnEdge.length;i++){
			pnts[i] = this.pointsOnEdge[this.pointsOnEdge.length-1-i];
		}
		return new Edge(pnts,this.length,this.minimumWidth,this.agentsOnEdge, this.efficiency, this.weight);
	}
	
	public Pnt getLastPoint(){
		return pointsOnEdge[pointsOnEdge.length-1];
	}

	public Pnt getSecondLastPoint(){
		if(pointsOnEdge.length == 1){
			return null;
		}
		return pointsOnEdge[pointsOnEdge.length-2];
	}

	public Pnt getFirstPoint(){
		return pointsOnEdge[0];
	}

	public Pnt getSecondPoint(){
		if(pointsOnEdge.length == 1){
			return null;
		}
		return pointsOnEdge[1];
	}
	
	public Pnt[] getPointsOnEdge(){
		return pointsOnEdge;
	}
	
	public double getWeight(){
		return weight;
	}
	
	public double getLength(){
		if(this.length == 0.0){
			double total = 0.0;
			for(int i = 0; i < pointsOnEdge.length-1 ;i++){
				total += pointsOnEdge[i].distanceTo(pointsOnEdge[i+1]);
			}
			this.length = total;
		}
		return length;
	}
	
	/*public Edge combine (Edge secondEdge){
		if(this.getFirstPoint().equals(secondEdge.getLastPoint())){
			return combinePoints(secondEdge,this);
		} else if(secondEdge.getFirstPoint().equals(this.getLastPoint())){
			return combinePoints(this, secondEdge);
		} else if(secondEdge.getFirstPoint().equals(this.getFirstPoint())){
			return combinePoints(this, secondEdge);
		} else if(secondEdge.getLastPoint().equals(this.getLastPoint())){
			return combinePoints(this, secondEdge);
		} else {
			System.out.println("edge can't be combined");
			for(Pnt pnt : this.getPointsOnEdge()){
				System.out.println("   "+pnt.coord(0)+"/"+pnt.coord(0));
			}
			System.out.println("VS");
			for(Pnt pnt : secondEdge.getPointsOnEdge()){
				System.out.println("   "+pnt.coord(0)+"/"+pnt.coord(0));
			}
			return null;
		}
	}*/

	public Edge combine(Edge edge2) {
		Edge edge1 = this;
		if(edge1.getFirstPoint().equals(edge2.getFirstPoint())){
			edge1 = edge1.reverse();
		} else if (edge1.getLastPoint().equals(edge2.getLastPoint())){
			edge2 = edge2.reverse();
		} else if (edge1.getFirstPoint().equals(edge2.getLastPoint())){
			edge1 = edge1.reverse();
			edge2 = edge2.reverse();
		} else if (edge1.getLastPoint().equals(edge2.getLastPoint())){
			//prima
		} else {
			System.out.println("wat een ellende! can't find simular point");
			for(Pnt pnt : edge1.getPointsOnEdge()){
				System.out.println("   "+pnt.coord(0)+"/"+pnt.coord(0));
			}
			System.out.println("VS");
			for(Pnt pnt : edge2.getPointsOnEdge()){
				System.out.println("   "+pnt.coord(0)+"/"+pnt.coord(0));
			}
			return null;
		}
		Pnt[] edge1Points = edge1.getPointsOnEdge();
		Pnt[] edge2Points = edge2.getPointsOnEdge();
		Pnt[] pnts = new Pnt[edge1Points.length+edge2Points.length-1];
		for(int i = 0; i < pnts.length; i++){
			if(i < edge1Points.length){
				pnts[i] = edge1Points[i];
			} else {
				pnts[i] = edge2Points[i-edge1Points.length+1];
			}
		}
		double totalLength = edge1.getLength() + edge2.getLength();
		double totalWeight = edge1.getWeight() + edge2.getWeight();
		HashSet<Agent> agentsOnEdge = new HashSet<Agent>();
		agentsOnEdge.addAll(edge1.agentsOnEdge);
		agentsOnEdge.addAll(edge2.agentsOnEdge);
		double minMinimumWidth = Math.min(edge1.getMinimumWidth(), edge2.getMinimumWidth());
		double maxEfficiency = Math.max(edge1.getEfficiency(), edge2.getEfficiency());
		return new Edge(pnts,totalLength,minMinimumWidth,agentsOnEdge,maxEfficiency,totalWeight);
	}

	@Override
	public int compareTo(Edge arg0) {
		if(this.getWeight() == arg0.getWeight()){
			return 0;
		} else if(this.getWeight() > arg0.getWeight()){
			return 1;
		}
		return -1;
	}

	public double getMinimumWidth(){
		return minimumWidth;
	}


	public void setMinimumWidth(double minimumWidth) {
		this.minimumWidth = minimumWidth;
		
	}


	public double distanceTo(Pnt pos) {
		return new Line2(new Line2(getFirstPoint(),getLastPoint()).closestPoint(pos),pos).length();
	}


	public void setEfficiency(double efficiency) {
		this.efficiency = efficiency;	
		this.weight = this.length / this.efficiency;
	}
	
	public double getEfficiency() {
		return efficiency;	
	}
}
